package gokyesil.game2d.actors;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.BSpline;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.Filter;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.JointEdge;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.DistanceJoint;
import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Array;

public class MapChain extends Button
{
	protected final float scale = 0.05f;
	protected final float unit = 5f;
	public Body[] ringList;
	public MapPlayer player;
	public MapBlock block;
	public DistanceJoint distanceJoint;
	public World physWorld;
	public MapChain(Texture texture, MapPlayer _player, MapBlock _block, World _physWorld)
	{
		super(new TextureRegionDrawable(new TextureRegion(texture)));
		this.setBackground(new TextureRegionDrawable(new TextureRegion(texture)),false);
		this.player = _player;
		this.block = _block;
		this.physWorld = _physWorld;
		//System.out.println(new Vector2(player.getX(),player.getY()));
		//System.out.println(new Vector2(block.getX(),block.getY()));
		//System.out.println();
		Vector2 from = player.getBody().getPosition();
		Vector2 to = block.getBody().getPosition();

		//System.out.println(from);
		//System.out.println(to);
		//System.out.println();
		
		float distance =  to.dst(from);
		int number = (int) (distance/(unit*scale));
		int numberOfRings = number/10;
		float angle = to.sub(from).angle();
		Vector2 unitVec = new Vector2((unit*scale),0).rotate(angle).scl(10);
		//System.out.println(unitVec);
		
		float radian = (float) (angle*(Math.PI/180));
		
		ringList = new Body[numberOfRings];
		
		Vector2 tempVec = new Vector2(from.x+unitVec.x,from.y+unitVec.y);
		//System.out.println(unitVec);
		Body prevBody = player.getBody();
		//System.out.println(unitVec);
		//System.out.println();
		for(int i=0; i<numberOfRings; i++)
		{   
			BodyDef bodyDef = new BodyDef();
	        bodyDef.type = BodyType.DynamicBody;
	        bodyDef.position.set(tempVec);
	        bodyDef.angle = radian;
	        
	        ringList[i] = physWorld.createBody(bodyDef);
		    PolygonShape dynamicBox = new PolygonShape();
		    dynamicBox.setAsBox((unit*scale), (unit*scale));
	        
		    FixtureDef fixtureDef = new FixtureDef();
		    fixtureDef.shape = dynamicBox;
		    fixtureDef.density = 2f; 
		    fixtureDef.friction = 0.01f;
		    fixtureDef.restitution = 0.01f;
		    fixtureDef.filter.groupIndex = -1;
		    ringList[i].createFixture(fixtureDef);
	        
	        /*RevoluteJointDef jointDef = new RevoluteJointDef();
	        jointDef.bodyA = prevBody;
	        jointDef.bodyB = ringList[i];
	        jointDef.localAnchorA.set(2*(unit*scale),0);
	        jointDef.localAnchorB.set(-2*(unit*scale),0);
//	        jointDef.initialize(prevBody, ringList[i], tempVec.sub(unitVec));
	        jointDef.enableLimit = true;
	        jointDef.collideConnected = false;    
	        jointDef.upperAngle = MathUtils.PI/24.0f;
	        jointDef.lowerAngle = -MathUtils.PI/24.0f;
	        physWorld.createJoint(jointDef);*/
		    
		    DistanceJointDef distanceDef = new DistanceJointDef();
		    distanceDef = new DistanceJointDef();
		    distanceDef.initialize(prevBody, ringList[i], prevBody.getPosition(), ringList[i].getPosition());
		   /* distanceDef.bodyA = prevBody;
		    distanceDef.bodyB = ringList[i];
		    distanceDef.localAnchorA.set(0,0);
		    distanceDef.localAnchorB.set(0,0);*/
		    distanceDef.collideConnected = false;
	        physWorld.createJoint(distanceDef);
	        
	        prevBody =  ringList[i];
	        tempVec.add(unitVec);
	        
		}
      /*  RevoluteJointDef jointDef = new RevoluteJointDef();
        //jointDef.initialize(prevBody, block.getBody(), tempVec);
        jointDef.bodyA = prevBody;
        jointDef.bodyB = block.getBody();
        jointDef.localAnchorA.set(2*(unit*scale),0);
        jointDef.localAnchorB.set(-2*(unit*scale),0);
       // jointDef.enableMotor = false;
     //   jointDef.enableLimit = true;
        jointDef.collideConnected = false;
        jointDef.upperAngle = MathUtils.PI/6.0f;
        jointDef.lowerAngle = -MathUtils.PI/6.0f;
        physWorld.createJoint(jointDef);*/
		
		DistanceJointDef distanceDef = new DistanceJointDef();
		distanceDef = new DistanceJointDef();
		distanceDef.initialize(prevBody, block.getBody(), prevBody.getPosition(), block.getBody().getPosition());
	   /* distanceDef.bodyA = prevBody;
	    distanceDef.bodyB = block.getBody();
	    distanceDef.localAnchorA.set(0,0);
	    distanceDef.localAnchorB.set(0,0);*/
		distanceDef.collideConnected = false;
        physWorld.createJoint(distanceDef);
        
	    /*DistanceJointDef distanceDef = new DistanceJointDef();
        distanceDef.initialize(prevBody, block.getBody(), prevBody.getPosition(), block.getBody().getPosition());
        distanceDef.collideConnected = false;
        physWorld.createJoint(distanceDef);*/
        
        Fixture fixture = player.getBody().getFixtureList().get(0);
        Filter filter = new Filter();
        filter.groupIndex = -1;
        fixture.setFilterData(filter);
        
        fixture = block.getBody().getFixtureList().get(0);
        filter = new Filter();
        filter.groupIndex = -1;
        fixture.setFilterData(filter);
        
       /* DistanceJointDef distanceJointDef = new DistanceJointDef();
        distanceJointDef.initialize(player.getBody(), block.getBody(), new Vector2(player.getBody().getPosition()).sub(unitVec), block.getBody().getPosition());
        distanceJointDef.collideConnected = false;
        distanceJoint = (DistanceJoint) physWorld.createJoint(distanceJointDef);*/
        
        //for (int i=0; i< ringList.length; i++) //System.out.println(ringList[i].getPosition());
        //System.out.println();
	}
	public void draw(Batch batch, float parentAlpha)
	{
		boolean isContact = false;
		if(physWorld.getContactList().size != 0)
		{
			for (int i=0; i< ringList.length; i++)
			{
		        for (Contact contact : physWorld.getContactList()) 
		        {
		            if(ringList[i] == contact.getFixtureA().getBody())
	            	{
		        		
		        		Vector2 point = contact.getWorldManifold().getPoints()[0];
		        		if(point.x == 0.0f && point.y == 0.0f) break;
		        		//System.out.println(point);
		        		//System.out.println();
		        		if(distanceJoint != null) physWorld.destroyJoint(distanceJoint);
		        		DistanceJointDef distanceJointDef = new DistanceJointDef();
		        		distanceJointDef.initialize(player.getBody(), contact.getFixtureB().getBody(), player.getBody().getPosition(), point);
		        		distanceJointDef.collideConnected = false;
		        		distanceJoint = (DistanceJoint) physWorld.createJoint(distanceJointDef);
		                isContact = true;
	            	}
		            if(ringList[i] == contact.getFixtureB().getBody())
	            	{
		        		
		        		Vector2 point = contact.getWorldManifold().getPoints()[0];
		        		if(point.x == 0.0f && point.y == 0.0f) break;
		        		//System.out.println(point);
		        		//System.out.println();
		        		if(distanceJoint != null) physWorld.destroyJoint(distanceJoint);
		        		DistanceJointDef distanceJointDef = new DistanceJointDef();
		        		distanceJointDef.initialize(player.getBody(), contact.getFixtureA().getBody(), player.getBody().getPosition(), point);
		        		distanceJointDef.collideConnected = false;
		        		distanceJoint = (DistanceJoint) physWorld.createJoint(distanceJointDef);
		                isContact = true;
	            	}      
		        }
			}
		}
	    if(!isContact)
	    {
	    	if(distanceJoint != null) physWorld.destroyJoint(distanceJoint);
	    	DistanceJointDef distanceJointDef = new DistanceJointDef();
	        distanceJointDef.initialize(player.getBody(), block.getBody(), player.getBody().getPosition(), block.getBody().getPosition());
	        distanceJointDef.collideConnected = false;
	        distanceJoint = (DistanceJoint) physWorld.createJoint(distanceJointDef);
	    }
	        
		
		if (this.getBackground() == null) return;
		Color color = getColor();
		batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);

		//for (int i=0; i< ringList.length; i++) //System.out.println(ringList[i].getPosition());
		//System.out.println();
		
		TextureRegion region = ((TextureRegionDrawable)this.getBackground()).getRegion();
    	Vector2 points[] = new Vector2[ringList.length+4];
    	points[0]=new Vector2().set(player.getBody().getPosition()).scl(1/scale);
    	points[1]= points[0];
    	
    	for(int i=2; i<ringList.length+2; i++) 
    		points[i] = new Vector2().set(ringList[i-2].getPosition()).scl(1/scale);
    	points[ringList.length+2]= new Vector2().set(block.getBody().getPosition()).scl(1/scale);
    	points[ringList.length+3] = points[ringList.length+2];
    	
    	//for (int i=0; i< points.length; i++) //System.out.println(points[i]);
    	//System.out.println();
    	
    	Vector2 p1 = new Vector2();
    	Vector2 p2 = new Vector2();
    	BSpline<Vector2> spline = new BSpline<Vector2>(points, 3, false);
    
    	for (float val=0.00f; val < 0.99f; val += 0.01f) 
    	{
    		spline.valueAt(/* out: */p1, val);
    		spline.valueAt(/* out: */p2, val+0.02f);
    		//System.out.println(p1);
    		//System.out.println(p2);
    		//System.out.println((p1.y+p2.y)/2.0f);
    		Vector2 dist = p2.sub(p1);
    		float angle = dist.angle();
    		float width = dist.len();
    		batch.draw(region, p1.x, p1.y-5, 0, 5, width, 10, 1, 1, angle);
    	    
    		//batch.draw(region, (p1.x+p2.x)/2.0f, (p1.y+p2.y)/2.0f, 0, 0, p1.dst(p2), 10, 1, 1, angle);
    	}
    	//for (int i=0; i< ringList.length; i++)
    		//batch.draw(region, points[i+2].x-5, points[i+2].y-5, 5, 5, 10, 10, 1, 1, (float) (ringList[i].getAngle()*(180/Math.PI)));
    	
    //	batch.draw(region,50,50,0,0,25,25,1,1,0);
   	}
	public void delete(World physWorld) 
	{
		for(int i=0; i<ringList.length; i++)
		{
			Array<JointEdge> jointsArray = ringList[i].getJointList();
			while(jointsArray.size != 0)
			{
				JointEdge jointEdge = jointsArray.pop();
				physWorld.destroyJoint(jointEdge.joint);
			}
			physWorld.destroyBody(ringList[i]);
			/*JointEdge[] joints = jointsArray.pop()
			for(int j=0; j<joints.length; j++)
				physWorld.destroyJoint(joints[j].joint);
			physWorld.destroyBody(ringList[i]);*/
		}
		
		Array<JointEdge> jointsArray = player.getBody().getJointList();
		while(jointsArray.size != 0)
		{
			JointEdge jointEdge = jointsArray.pop();
			physWorld.destroyJoint(jointEdge.joint);
		}
		
		jointsArray = block.getBody().getJointList();
		while(jointsArray.size != 0)
		{
			JointEdge jointEdge = jointsArray.pop();
			physWorld.destroyJoint(jointEdge.joint);
		}
	}
	public MapChain clone(MapPlayer backupPlayer, MapBlock chainedBlock, World backupWorld) 
	{
		Texture texture = ((TextureRegionDrawable)this.getBackground()).getRegion().getTexture();
		return new MapChain(texture,backupPlayer,chainedBlock,backupWorld);
	}
}
